package com.insight.modules.system.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xkcoding.justauth.AuthRequestFactory;
import com.yuanqiao.insight.common.util.common.RedisUtils;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.utils.AuthStateUtils;
import com.insight.common.api.vo.Result;
import com.insight.common.constant.CommonConstant;
import com.insight.common.system.util.JwtUtil;
import com.insight.common.util.PasswordUtil;
import com.insight.common.util.oConvertUtils;
import com.insight.modules.base.service.BaseCommonService;
import com.insight.modules.system.entity.SysThirdAccount;
import com.insight.modules.system.entity.SysUsers;
import com.insight.modules.system.model.ThirdLoginModel;
import com.insight.modules.system.service.ISysThirdAccountService;
import com.insight.modules.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

/**
 * @Author scott
 * @since 2018-12-17
 */
@Controller
@RequestMapping("/sys/thirdLogin")
@Slf4j
public class ThirdLoginController {

	@Autowired
	private ISysUserService sysUserService;
	@Autowired
	private ISysThirdAccountService sysThirdAccountService;
	@Autowired
	private BaseCommonService baseCommonService;
	@Autowired
	private RedisUtils redisUtil;
	@Autowired
	private AuthRequestFactory factory;
	@Autowired
	private JwtUtil jwtUtil;

	/**
	 * 第三方登录入口，重定向到第三方授权页面
	 *
	 * @param source   第三方登录来源标识，如 "github", "wechat"
	 * @param response HttpServletResponse 用于重定向
	 * @throws IOException 重定向异常
	 */
	@RequestMapping("/render/{source}")
	public void render(@PathVariable("source") String source, HttpServletResponse response) throws IOException {
		log.info("第三方登录进入render：" + source);
		AuthRequest authRequest = factory.get(source);
		String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
		log.info("第三方登录认证地址：" + authorizeUrl);
		response.sendRedirect(authorizeUrl);
	}

	/**
	 * 第三方登录回调处理
	 *
	 * @param source    第三方登录来源
	 * @param callback  第三方认证回调参数
	 * @param modelMap  返回视图数据模型
	 * @return 跳转页面名
	 */
	@RequestMapping("/{source}/callback")
	public String loginThird(@PathVariable("source") String source, AuthCallback callback, ModelMap modelMap) {
		log.info("第三方登录进入callback：" + source + " params：" + JSONObject.toJSONString(callback));
		AuthRequest authRequest = factory.get(source);
		AuthResponse response = authRequest.login(callback);
		log.info(JSONObject.toJSONString(response));
		Result<JSONObject> result = new Result<>();
		if (response.getCode() == 2000) {
			JSONObject data = JSONObject.parseObject(JSONObject.toJSONString(response.getData()));
			String username = data.getString("username");
			String avatar = data.getString("avatar");
			String uuid = data.getString("uuid");

			// 构造第三方登录信息存储对象
			ThirdLoginModel tlm = new ThirdLoginModel(source, uuid, username, avatar);

			// 查询第三方账户是否存在
			LambdaQueryWrapper<SysThirdAccount> query = new LambdaQueryWrapper<>();
			query.eq(SysThirdAccount::getThirdUserUuid, uuid);
			query.eq(SysThirdAccount::getThirdType, source);
			List<SysThirdAccount> thridList = sysThirdAccountService.list(query);

			SysThirdAccount user = null;
			if (thridList == null || thridList.isEmpty()) {
				// 账户不存在则创建新账号
				user = saveThirdUser(tlm);
			} else {
				// 已存在只设置用户名，不设置头像
				user = thridList.get(0);
			}

			// 生成JWT token，如果绑定了系统用户则返回token，否则提示绑定手机号
			if (oConvertUtils.isNotEmpty(user.getSysUserId())) {
				String sysUserId = user.getSysUserId();
				SysUsers sysUser = sysUserService.getById(sysUserId);
				String token = saveToken(sysUser);
				modelMap.addAttribute("token", token);
			} else {
				modelMap.addAttribute("token", "绑定手机号," + "" + uuid);
			}
		} else {
			modelMap.addAttribute("token", "登录失败");
		}
		result.setSuccess(false);
		result.setMessage("第三方登录异常,请联系管理员");
		return "thirdLogin";
	}

	/**
	 * 创建新第三方账户信息
	 *
	 * @param model 第三方登录模型
	 * @return 新建的 SysThirdAccount 实体
	 */
	@PostMapping("/user/create")
	@ResponseBody
	public Result<String> thirdUserCreate(@RequestBody ThirdLoginModel model) {
		log.info("第三方登录创建新账号：");
		Result<String> res = new Result<>();
		Object operateCode = redisUtil.get(CommonConstant.THIRD_LOGIN_CODE);
		if (operateCode == null || !operateCode.toString().equals(model.getOperateCode())) {
			res.setSuccess(false);
			res.setMessage("校验失败");
			return res;
		}
		// 创建新账号
		SysThirdAccount user = saveThirdUser(model);
		if (oConvertUtils.isNotEmpty(user.getSysUserId())) {
			String sysUserId = user.getSysUserId();
			SysUsers sysUser = sysUserService.getById(sysUserId);
			String token = saveToken(sysUser);
			res.setResult(token);
			res.setSuccess(true);
		}
		return res;
	}

	/**
	 * 校验密码并绑定第三方账户到系统账户，生成token
	 *
	 * @param json JSON参数，包含uuid、password、operateCode等
	 * @return 操作结果及token
	 */
	@PostMapping("/user/checkPassword")
	@ResponseBody
	public Result<String> checkPassword(@RequestBody JSONObject json) {
		Result<String> result = new Result<>();
		Object operateCode = redisUtil.get(CommonConstant.THIRD_LOGIN_CODE);
		if (operateCode == null || !operateCode.toString().equals(json.getString("operateCode"))) {
			result.setSuccess(false);
			result.setMessage("校验失败");
			return result;
		}
		String username = json.getString("uuid");
		SysUsers user = sysUserService.getUserByName(username);
		if (user == null) {
			result.setMessage("用户未找到");
			result.setSuccess(false);
			return result;
		}
		String password = json.getString("password");
		String salt = user.getSalt();
		String passwordEncode = PasswordUtil.encrypt(user.getUsername(), password, salt);
		if (!passwordEncode.equals(user.getPassword())) {
			result.setMessage("密码不正确");
			result.setSuccess(false);
			return result;
		}
		sysUserService.updateById(user);
		result.setSuccess(true);
		String token = saveToken(user);
		result.setResult(token);
		return result;
	}

	/**
	 * 保存第三方账户信息到数据库
	 *
	 * @param tlm 第三方登录信息
	 * @return 保存的 SysThirdAccount 实体
	 */
	private SysThirdAccount saveThirdUser(ThirdLoginModel tlm) {
		SysThirdAccount user = new SysThirdAccount();
		user.setDelFlag(CommonConstant.DEL_FLAG_0);
		user.setStatus(1);
		user.setThirdType(tlm.getSource());
		user.setAvatar(tlm.getAvatar());
		user.setRealname(tlm.getUsername());
		user.setThirdUserUuid(tlm.getUuid());
		sysThirdAccountService.save(user);
		return user;
	}

	/**
	 * 生成并缓存JWT Token
	 *
	 * @param user 系统用户实体
	 * @return 生成的Token字符串
	 */
	private String saveToken(SysUsers user) {
		String token = jwtUtil.sign(user.getUsername(), user.getPassword());
		redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
		redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, jwtUtil.getTime());
		return token;
	}

	/**
	 * 通过token和第三方类型获取登录用户信息
	 *
	 * @param token     JWT Token
	 * @param thirdType 第三方登录类型
	 * @return 用户信息及token
	 * @throws Exception 异常
	 */
	@SuppressWarnings("unchecked")
	@RequestMapping(value = "/getLoginUser/{token}/{thirdType}", method = RequestMethod.GET)
	@ResponseBody
	public Result<JSONObject> getThirdLoginUser(@PathVariable("token") String token, @PathVariable("thirdType") String thirdType) {
		Result<JSONObject> result = new Result<>();
		String username = JwtUtil.getUsername(token);

		// 校验用户是否有效
		SysUsers sysUser = sysUserService.getUserByName(username);
		result = sysUserService.checkUserIsEffective(sysUser);
		if (!result.isSuccess()) {
			return result;
		}

		// 获取第三方账户信息，补充真实姓名和头像
		LambdaQueryWrapper<SysThirdAccount> query = new LambdaQueryWrapper<>();
		query.eq(SysThirdAccount::getSysUserId, sysUser.getId());
		query.eq(SysThirdAccount::getThirdType, thirdType);
		SysThirdAccount account = sysThirdAccountService.getOne(query);
		if (oConvertUtils.isEmpty(sysUser.getRealname())) {
			sysUser.setRealname(account.getRealname());
		}
		if (oConvertUtils.isEmpty(sysUser.getAvatar())) {
			sysUser.setAvatar(account.getAvatar());
		}

		JSONObject obj = new JSONObject();
		obj.put("userInfo", sysUser);
		obj.put("token", token);
		result.setResult(obj);
		result.setSuccess(true);
		result.setCode(200);
		baseCommonService.addLog("用户名: " + username + ",登录成功[第三方用户]！", CommonConstant.LOG_TYPE_1, null);
		return result;
	}

	/**
	 * 绑定手机号接口，校验手机号和验证码，绑定第三方账号并返回token
	 *
	 * @param jsonObject 请求参数，包含手机号、第三方UUID及验证码
	 * @return 绑定结果及token
	 */
	@ApiOperation("手机号登录接口")
	@PostMapping("/bindingThirdPhone")
	@ResponseBody
	public Result<String> bindingThirdPhone(@RequestBody JSONObject jsonObject) {
		Result<String> result = new Result<>();
		String phone = jsonObject.getString("mobile");
		String thirdUserUuid = jsonObject.getString("thirdUserUuid");

		// 校验手机号对应用户
		SysUsers sysUser = sysUserService.getUserByPhone(phone);
		if (sysUser != null) {
			// 更新第三方用户绑定关系
			sysThirdAccountService.updateThirdUserId(sysUser, thirdUserUuid);
		} else {
			// 手机号不存在，校验验证码并创建用户
			String smscode = jsonObject.getString("captcha");
			Object code = redisUtil.get(phone);
			if (!smscode.equals(code)) {
				result.setMessage("手机验证码错误");
				result.setSuccess(false);
				return result;
			}
			sysUser = sysThirdAccountService.createUser(phone, thirdUserUuid);
		}

		// 生成token返回
		String token = saveToken(sysUser);
		result.setSuccess(true);
		result.setResult(token);
		return result;
	}
}

